package com.daffodil.cms.service.impl;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.daffodil.cms.entity.CmsChannel;
import com.daffodil.cms.service.ICmsChannelService;
import com.daffodil.core.constant.Constants;
import com.daffodil.core.dao.JpaDao;
import com.daffodil.core.entity.Query;
import com.daffodil.core.exception.BaseException;
import com.daffodil.util.HqlUtils;
import com.daffodil.util.StringUtils;

/**
 * 栏目（站点）管理
 * @author yweijian
 * @date 2019年12月18日
 * @version 1.0
 */
@Service
public class CmsChannelServiceImpl implements ICmsChannelService {
	
	@Autowired
	private JpaDao<String> jpaDao;

	@Override
	public List<CmsChannel> selectChannelList(Query<CmsChannel> query) {
		List<Object> paras = new ArrayList<Object>();
		StringBuffer hql = new StringBuffer("from CmsChannel c where 1=1 ");
		HqlUtils.createHql(hql, paras, query, "c");
		hql.append("order by c.orderNum asc,c.ancestors asc");
		return jpaDao.search(hql.toString(), paras, CmsChannel.class, query.getPage());
	}

	@Override
	public List<CmsChannel> channelTreeData(Query<CmsChannel> query) {
		List<CmsChannel> channelList = this.selectChannelList(query);
		List<CmsChannel> ztrees = this.initZtree(channelList);
		return ztrees;
	}

	/**
	 * 初始化zTree
	 * @param channels 栏目（站点）列表
	 * @return 树结构列表
	 */
	public List<CmsChannel> initZtree(List<CmsChannel> channels) {
		List<CmsChannel> ztrees = new ArrayList<CmsChannel>();
		for (CmsChannel channel : channels) {
			if (Constants.NORMAL.equals(channel.getStatus())) {
				CmsChannel ztree = channel;
				ztree.setpId(channel.getParentId());
				ztree.setName(channel.getChannelName());
				ztree.setTitle(channel.getChannelName());
				ztrees.add(ztree);
			}
		}
		return ztrees;
	}

	@Override
	@Transactional
	public void deleteChannelById(String channelId) {
		int count = jpaDao.count("from CmsChannel where parentId = ?", channelId);
		if(count > 0){
			throw new BaseException("删除栏目（站点）失败，存在下级栏目，不允许删除");
		}
		jpaDao.delete(CmsChannel.class, channelId);
	}

	/**
	 * 栏目名称可以重复，站点名称不允许重复
	 */
	@Override
	@Transactional
	public void insertChannel(CmsChannel channel) {
		if(Constants.ROOT.equals(channel.getParentId())) {//站点
			if (this.checkChannelNameUnique(channel)) {
				throw new BaseException("新增站点【" + channel.getChannelName() + "】失败，站点名称已存在");
			}
		}
		
		CmsChannel parent = this.selectChannelById(channel.getParentId());
		if(StringUtils.isNotEmpty(parent.getAncestors())){
			channel.setAncestors(parent.getAncestors() + "," + channel.getParentId());
		}else{
			channel.setAncestors(channel.getParentId());
		}
		channel.setSiteId(parent.getSiteId());//父栏目的站点ID
		jpaDao.save(channel);
		
		if(Constants.ROOT.equals(channel.getParentId())) {//站点
			channel.setSiteId(channel.getId());
			jpaDao.update(channel);
		}
	}

	@Override
	@Transactional
	public void updateChannel(CmsChannel channel) {
		if(Constants.ROOT.equals(channel.getParentId())) {//站点
			if (this.checkChannelNameUnique(channel)) {
				throw new BaseException("新增站点【" + channel.getChannelName() + "】失败，站点名称已存在");
			}
		}
		
		if (checkChannelIsSelfOrChildren(channel)) {
			throw new BaseException("修改栏目【" + channel.getChannelName() + "】失败，上级栏目不能是自己或自己的子栏目");
		}
		
		CmsChannel cmsChannel = this.selectChannelById(channel.getId());
		
		if(Constants.ROOT.equals(cmsChannel.getParentId()) && !cmsChannel.getParentId().equals(channel.getParentId())) {
			throw new BaseException("移动站点【" + channel.getChannelName() + "】失败，站点不允许移动");
		}
		
		CmsChannel parent = this.selectChannelById(channel.getParentId());
		
		if(!Constants.ROOT.equals(parent.getId()) && !cmsChannel.getSiteId().equals(parent.getSiteId())) {//子父站点ID不一致
			throw new BaseException("移动栏目【" + channel.getChannelName() + "】失败，栏目不允许跨站点移动");
		}
		
		if (StringUtils.isNotNull(parent) && StringUtils.isNotNull(cmsChannel)) {
			String newAncestors = parent.getAncestors() + "," + parent.getId();
			String oldAncestors = cmsChannel.getAncestors();
			channel.setAncestors(newAncestors);
			this.updateChildrenChannel(channel, newAncestors, oldAncestors);
		}
		jpaDao.update(channel);
	}
	
	/**
	 * 检查栏目是否是自己或自己的子栏目
	 * @param channel
	 * @return
	 */
	public boolean checkChannelIsSelfOrChildren(CmsChannel channel){
		List<Object> paras = new ArrayList<Object>();
		String hql = "from CmsChannel where id = ? or ancestors like ?";
		paras.add(channel.getId());
		paras.add("%" + channel.getId() + "%");
		List<CmsChannel> channels = jpaDao.search(hql, paras, CmsChannel.class);
		for(CmsChannel sysCmsChannel : channels){
			if(channel.getParentId().equals(sysCmsChannel.getId())){
				return true;
			}
		}
		return false;
	}

	@Transactional
	public void updateChildrenChannel(CmsChannel channel, String newAncestors, String oldAncestors) {
		//查询旧的前缀的所有子栏目
		List<CmsChannel> childrens = jpaDao.search("from CmsChannel where ancestors like ?", "%" + channel.getId() + "%", CmsChannel.class);
		for (CmsChannel child : childrens) {
			//替换掉所有子栏目的前缀
			child.setAncestors(child.getAncestors().replace(oldAncestors, newAncestors));
			//父栏目状态改变，子栏目也变更
			child.setStatus(channel.getStatus());
			jpaDao.update(child);
		}
	}

	@Override
	public CmsChannel selectChannelById(String channelId) {
		if(Constants.ROOT.equals(channelId)){
			CmsChannel channel = new CmsChannel();
			channel.setId(Constants.ROOT);
			channel.setChannelName("根站点");
			channel.setAncestors("");
			return channel;
		}
		CmsChannel channel = jpaDao.find(CmsChannel.class, channelId);
		CmsChannel site = jpaDao.find(CmsChannel.class, channel.getSiteId());
		channel.setSiteName(site.getChannelName());
		return channel;
	}

	@Override
	public boolean checkChannelNameUnique(CmsChannel channel) {
		List<Object> paras = new ArrayList<Object>();
		String hql = "from CmsChannel where channelName=? and parentId=? ";
		paras.add(channel.getChannelName());
		paras.add(channel.getParentId());
		if(StringUtils.isNotEmpty(channel.getId())){
			hql += "and id != ?";
			paras.add(channel.getId());
		}
		CmsChannel sysCmsChannel = jpaDao.find(hql, paras, CmsChannel.class);
		if (StringUtils.isNotNull(sysCmsChannel)) {
			return Constants.NOT_UNIQUE;
		}
		return Constants.IS_UNIQUE;
	}

	@Override
	@Transactional
	public void batchAddChannel(String parentId, String channels) {
		CmsChannel channel = jpaDao.find(CmsChannel.class, parentId);
		if(StringUtils.isNull(channel)) {
			throw new BaseException("批量新增栏目失败，父级栏目（站点）不能为空");
		}
		if(StringUtils.isNotEmpty(channels)) {
			List<String> ancestors = new ArrayList<String>();
			ancestors.add(parentId);
			
			channels = channels.trim();
			BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(channels.getBytes(Charset.forName("utf8"))), Charset.forName("utf8")));
			
			try {
				String line = null;
				while(StringUtils.isNotEmpty(line = reader.readLine())){
					String channelName = line.replaceAll("\\t", "");
					int level = line.length() - channelName.length();//栏目级别
					int size = ancestors.size();
					parentId = ancestors.get(level);
					
					if(StringUtils.isNotEmpty(parentId)) {
						CmsChannel children = new CmsChannel();
						children.setChannelName(channelName.trim());
						children.setStatus(Constants.NORMAL);
						children.setOrderNum(level + 1L);
						children.setParentId(parentId);
						
						this.insertChannel(children);
						
						if(size - level == 1) {
							ancestors.add(children.getId());
						}else if(size - level == 2) {
							ancestors.set(level + 1, children.getId());
						}else {
							ancestors.set(level + 1, children.getId());
							for(int i = 0; i < (size - level - 2); i++) {
								ancestors.remove(ancestors.size() - 1);
							}
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
				throw new BaseException("批量新增栏目失败");
			}
			
		}
	}
}
